﻿using System;
using System.Data.SqlClient;
using System.IO;
using System.Windows.Forms;

namespace RecoverSP2010Files
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (tbDBConnStr.Text != string.Empty)
                GetDirectories(tbDBConnStr.Text);
        }

        private void GetDirectories(string connstr)
        {
            try
            {
                //clear existing entries
                cboDirectories.Items.Clear();

                //Let's get all the directories it knows in the DB
                using (SqlConnection conn = new SqlConnection(connstr))
                {
                    SqlCommand cmd = new SqlCommand("select docs.DirName from AllDocs docs where (dirname <> '') and HasStream=1 and LeafName not like '%.aspx' group by dirname", conn);
                    conn.Open();

                    SqlDataReader rdr = cmd.ExecuteReader();
                    while (rdr.Read())
                    {
                        cboDirectories.Items.Add(rdr["DirName"].ToString());
                    }

                    rdr.Close();
                }

                cboDirectories.SelectedIndex = 0;
                //if we got this far then lets get the files for the first directory & display them
                GetFiles(connstr, cboDirectories.Items[0].ToString());
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Something went wrong", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void GetFiles(string connstr, string directory)
        {
            try
            {
                //clear existing entries
                clbFiles.Items.Clear();

                //Let's get all the files in the directory
                using (SqlConnection conn = new SqlConnection(connstr))
                {
                    string query = string.Format("SELECT docs.Id, docs.DirName, docs.LeafName, docs.TimeLastModified from AllDocs docs where (dirname = '{0}') and HasStream=1 and LeafName not like '%.aspx' order by LeafName, TimeLastModified desc", directory);

                    SqlCommand cmd = new SqlCommand(query, conn);

                    conn.Open();

                    SqlDataReader rdr = cmd.ExecuteReader();
                    while (rdr.Read())
                    {
                        SPFile file = new SPFile
                        {
                            ID = rdr["Id"].ToString(),
                            Directory = rdr["DirName"].ToString(),
                            FileName = rdr["LeafName"].ToString(),
                            TimeLastModified = DateTime.Parse(rdr["TimeLastModified"].ToString())
                        };
                        clbFiles.Items.Add(file);
                    }
                    rdr.Close();
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Something went wrong", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnSelectDirectory_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialog1.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
                tbOutputPath.Text = folderBrowserDialog1.SelectedPath;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            tbDBConnStr.Text = Properties.Settings.Default.DBConnStr;
            tbOutputPath.Text = Properties.Settings.Default.OutputPath;
            clbFiles.DisplayMember = "DisplayMember";
            clbFiles.ValueMember = "FileName";
        }

        private void cboDirectories_SelectedIndexChanged(object sender, EventArgs e)
        {
            GetFiles(tbDBConnStr.Text, cboDirectories.SelectedItem.ToString());
        }

        private void btnExtractFiles_Click(object sender, EventArgs e)
        {
            if (tbOutputPath.Text == string.Empty)
            {
                MessageBox.Show("Invalid output path");
                return;
            }

            foreach (var item in clbFiles.CheckedItems)
            {
                SPFile file = (SPFile)item;

                //don't bother to create the file if we've already got it
                if (!File.Exists(tbOutputPath.Text + "/" + file.FileName))
                {
                    try
                    {
                        using (SqlConnection conn = new SqlConnection(tbDBConnStr.Text))
                        {
                            SqlCommand cmd = new SqlCommand(string.Format("select ads.content from AllDocStreams ads  where  ads.Id = '{0}'", file.ID), conn);

                            conn.Open();
                            SqlDataReader rdr = cmd.ExecuteReader();

                            while (rdr.Read())
                            {

                                //Create a FileStream to create the file
                                FileStream fs = new FileStream(tbOutputPath.Text + "/" + file.FileName, FileMode.Create, FileAccess.Write);
                                BinaryWriter writer = new BinaryWriter(fs);

                                int bufferSize = 1048576; //1Mb
                                long startIndex = 0;
                                long retval = 0;
                                byte[] outByte = new byte[bufferSize];

                                // Grab the file 1Mb at a time & write it out
                                do
                                {
                                    retval = rdr.GetBytes(0, startIndex, outByte, 0, bufferSize);
                                    startIndex += bufferSize;

                                    writer.Write(outByte, 0, (int)retval);
                                    writer.Flush();
                                } while (retval == bufferSize);

                                writer.Close();
                                fs.Close();
                            }

                            rdr.Close();
                        }
                    }
                    catch (Exception exc)
                    {
                        MessageBox.Show(exc.Message);
                    }
                }
            }
            MessageBox.Show("Done");
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.DBConnStr = tbDBConnStr.Text;
            Properties.Settings.Default.OutputPath = tbOutputPath.Text;
            Properties.Settings.Default.Save();
        }
    }
}
